package com.syscom.server.qd.cacheManager;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.syscom.frmcommon.util.ArithUtil;
import com.syscom.safe.util.xml.XmlAggregate;
import com.syscom.safe.util.xml.XmlElement;
import com.syscom.safe.wac.management.SacManager;
import com.syscom.server.qd.vo.ConfigRatio;

public class GlobalConfigManager {
	private static Logger mLogger = Logger.getLogger(GlobalConfigManager.class.getName());
	
	private Map<String, ConfigRatio> map = new Hashtable<String, ConfigRatio>();
	
	private static GlobalConfigManager instance = new GlobalConfigManager();
	
	private static double mdThresholdRate;
	
	private String[] msServerIds;
	
	// ms
	private long lDrawBackTimeout;
	
	public static GlobalConfigManager getInstance() {
		return instance;
	}
	
	private GlobalConfigManager() {
		initRatio();
		
		initThreshold();
		
		checkRate();
		
		initDrawBackTimeout();
	}

	private void initRatio() {
		XmlAggregate xmlAggregate = SacManager.getInstance().getGlobalConfig("quota-dipatch-ratio");

		if(xmlAggregate == null) {
			mLogger.fatal("global-params config : <quota-dipatch-ratio> not exist.");
			mLogger.fatal("Server ShutDown.");
			SacManager.getInstance().shutdown();
		}
		
		//
		List<String> lstServerId = new ArrayList<String>();
		@SuppressWarnings("unchecked")
		List<XmlAggregate> lstServerAggr = xmlAggregate.getAggregates("server");
		for(XmlAggregate serverAggr : lstServerAggr) {
			String sServerId = serverAggr.getAttribValue("id");
			lstServerId.add(sServerId);
			String sServerRatio = serverAggr.getAttribValue("server-ratio");
			
			ConfigRatio configRatio = new ConfigRatio();
			configRatio.setServerId(sServerId);
			if(sServerRatio == null) {
				mLogger.fatal("global-params config : <server-ratio> attribute not exist.");
				mLogger.fatal("Server ShutDown.");
				SacManager.getInstance().shutdown();
			}
			int iServerRatio = Integer.parseInt(sServerRatio);
			configRatio.setServerRatio(iServerRatio);
			
			@SuppressWarnings("unchecked")
			List<XmlElement> lstRuleEle = serverAggr.getElements("rule");
			for(XmlElement e : lstRuleEle) {
				String sRuleId = e.getAttribValue("id");
				int iRuleId = Integer.parseInt(sRuleId);
				String sRatio = e.getAttribValue("ratio");
				if(sRatio != null) {
					int iRatio = Integer.parseInt(sRatio);
					configRatio.setRuleRatio(iRuleId, iRatio);
				}
			}
			
			map.put(sServerId, configRatio);
		}
		
		msServerIds = new String[lstServerId.size()];
		lstServerId.toArray(msServerIds);
		
		@SuppressWarnings("unchecked")
		List<XmlElement> lstServerEle = xmlAggregate.getElements("server");
		for(XmlElement e : lstServerEle) {
			String sServerId = e.getAttribValue("id");
			String sServerRatio = e.getAttribValue("server-ratio");
			
			ConfigRatio configRatio = new ConfigRatio();
			configRatio.setServerId(sServerId);
			if(sServerRatio == null) {
				mLogger.fatal("global-params config : <server-ratio> attribute not exist.");
				mLogger.fatal("Server ShutDown.");
				SacManager.getInstance().shutdown();
			}
			int iServerRatio = Integer.parseInt(sServerRatio);
			configRatio.setServerRatio(iServerRatio);
			
			map.put(sServerId, configRatio);
		}
	}
	
	private void initThreshold() {
		XmlAggregate xmlAggregate = SacManager.getInstance().getGlobalConfig("quota-dipatch-ratio");
		
		XmlElement xmlElement = xmlAggregate.getElement("threshold");
		String sThresholdRate = xmlElement.getAttribValue("rate");
		mdThresholdRate = Double.parseDouble(sThresholdRate);
		mdThresholdRate = ArithUtil.div(mdThresholdRate, 100);
	}
	
	private void checkRate() {
		List<Integer> lstRules = RuleQtaCacheManager.getInstance().getAllRuleIds();
		Integer[] iRuleIds = new Integer[lstRules.size()];
		lstRules.toArray(iRuleIds);
		
		// 檢查百分比是否大於1
		for(int j = 0 ; j < iRuleIds.length ; j++) {
			
			double dRuleRate = 0;
			for(int i = 0 ; i < msServerIds.length ; i++) {
				dRuleRate = ArithUtil.add(dRuleRate, getRatio(msServerIds[i], iRuleIds[j]));
			}
			if(dRuleRate > 1) {
				mLogger.fatal("Rule " + iRuleIds[j] + " Dispatch Rate > 1.");
				mLogger.fatal("Server ShutDown.");
				SacManager.getInstance().shutdown();
			}
		}
	}
	
	private void initDrawBackTimeout() {
		XmlAggregate xmlAggregate = SacManager.getInstance().getGlobalConfig("draw-back-timeout");
		
		if(xmlAggregate == null) {
			mLogger.fatal("global-params config : <draw-back-timeout> not exist.");
			mLogger.fatal("Server ShutDown.");
			SacManager.getInstance().shutdown();
		}
		
		List<XmlElement> lst = xmlAggregate.getElements();
		
		for(XmlElement element : lst) {
			String sTimeout = element.getAttribValue("value");
			lDrawBackTimeout = Long.parseLong(sTimeout);
		}
	}
	
	public double getRatio(String sServerId, int iRuleId) {
		if(!map.containsKey(sServerId)) {
			return 0;
		}
		
		ConfigRatio configRatio = map.get(sServerId);
		double dRuleRatio = configRatio.getRuleRatio(iRuleId);
		
		if(dRuleRatio != 0) {
			return dRuleRatio;
		} else {
			double dServerRatio = configRatio.getServerRatio();
			if(dServerRatio != 0) {
				return dServerRatio;
			}
		}
		return 0;
	}
	
	public String[] getServerIdList() {
		return msServerIds;
	}
	
	public double getThreshold() {
		return mdThresholdRate;
	}
	
	public long getDrawBackTimeout() {
		return lDrawBackTimeout;
	}
}
